/*
    2021-06-15 写了DES的加密过程，解密过程还没有写
*/

#include <iostream>
#include <string>

using namespace std;
//初始置换IP
int IP[] = {
            58, 50, 42, 34, 26, 18, 10, 2, 
            60, 52, 44, 36, 28, 20, 12, 4,
            62, 54, 46, 38, 30, 22, 14, 6, 
            64, 56, 48, 40, 32, 24, 16, 8,
            57, 49, 41, 33, 25, 17,  9, 1, 
            59, 51, 43, 35, 27, 19, 11, 3,
            61, 53, 45, 37, 29, 21, 13, 5,
            63, 55, 47, 39, 31, 23, 15, 7 
};
//逆初始置换IP
int _IP[] = {
            40, 8, 48, 16, 56, 24, 64, 32,
			39, 7, 47, 15, 55, 23, 63, 31,
			38, 6, 46, 14, 54, 22, 62, 30,
			37, 5, 45, 13, 53, 21, 61, 29,
			36, 4, 44, 12, 52, 20, 60, 28,
			35, 3, 43, 11, 51, 19, 59, 27,
			34, 2, 42, 10, 50, 18, 58, 26,
			33, 1, 41,  9, 49, 17, 57, 25
};
//密钥置换IP1
int IP_1[] = {
            57, 49, 41, 33, 25, 17, 9,  
             1, 58, 50, 42, 34, 26, 18,
            10,  2, 59, 51, 43, 35, 27, 
            19, 11,  3, 60, 52, 44, 36, 
            63, 55, 47, 39, 31, 23, 15, 
             7, 62, 54, 46, 38, 30, 22,
            14,  6, 61, 53, 45, 37, 29,
            21, 13,  5, 28, 20, 12,  4 
};
//密钥置换IP2
int IP_2[] = {
            14, 17, 11, 24,  1,  5,  
             3, 28, 15,  6, 21, 10,
            23, 19, 12,  4, 26,  8, 
            16,  7, 27, 20, 13,  2,
            41, 52, 31, 37, 47, 55, 
            30, 40, 51, 45, 33, 48,
            44, 49, 39, 56, 34, 53, 
            46, 42, 50, 36, 29, 32
};
//循环左移次数
int left_16[] = {
            1, 1, 2, 2, 2, 2, 2, 2,
            1, 2, 2, 2, 2, 2, 2, 1
};
//选择运算扩展矩阵
int expand_48[] = {
            32,  1,  2,  3,  4,  5, 
             4,  5,  6,  7,  8,  9,
             8,  9, 10, 11, 12, 13,
            12, 13, 14, 15, 16, 17,
            16, 17, 18, 19, 20, 21,
            20, 21, 22, 23, 24, 25,
            24, 25, 26, 27, 28, 29,
            28, 29, 30, 31, 32,  1
};
//S盒
int S_box[8][4][16] = {
    //S1
    {   {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
		{0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},
		{4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},
		{15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}
	},
	//S2
	{   {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},
		{3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},
		{0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},
		{13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}
	},
	//S3
	{   {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},
		{13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},
		{13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},
		{1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}
	},
	//S4
	{   {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},
		{13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},
		{10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},
		{3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}
	},
	//S5
	{   {2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},
		{14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},
		{4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},
		{11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}
	},
	//S6
	{   {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},
		{10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},
		{9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},
		{4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}
	},
	//S7
	{   {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},
		{13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},
		{1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},
		{6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}
	},
	//S8
	{   {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},
		{1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},
		{7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},
		{2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}
	}
};
int P[] = {
        16,  7, 20, 21, 29, 12, 28, 17,
         1, 15, 23, 26,  5, 18, 31, 10,
         2,  8, 24, 14, 32, 27,  3,  9,
        19, 13, 30,  6, 22, 11,  4, 25
};
void display(string str);

//明文置换函数
string m_displace(string m) {
    string res = "";
    for(int i=0; i<64; ++i) {
        res += m[IP[i]-1];
    }
    return res;
}
//密文置换函数1
string k_displace1(string k) {
    string res = "";
    for(int i=0; i<56; ++i) {
        res += k[IP_1[i]-1];
    }
    return res;
}
//循环左移函数
string rotate_left(string str, int time) {
    for(int i=0; i<left_16[time]; ++i) {
        str += str[i];
    }
    return str.substr(left_16[time]);
}
//密钥置换函数2
string k_displace2(string str) {
    string res = "";
    for(int i=0; i<48; ++i) {
        res += str[IP_2[i]-1];
    }
    return res;
    }
//密钥置换函数3
string k_displace3(string str) {
    string res = "";
    for(int i=0; i<32; ++i) {
        res += str[P[i]-1];
    }
    return res;
}
//选择函数E
string expand(string str) {
    string res = "";
    for(int i=0; i<48; ++i){
        res += str[expand_48[i]-1];
    }
    return res;
}
// 模2加法函数
string add(string l, string k) {
    string res = "";
    for(int i=0; i<l.length(); ++i) {
        if(l[i] == '0' && k[i] == '0' || l[i] == '1' && k[i] == '1')
            res += '0';
        else res += '1';  
    }
    return res;
}
//单个S盒查询函数
string choice(string str, int number) {
    int row=0, column=0;
    if(str[0] == '1')   row += 2;
    else                row += 0;
    if(str[5] == '1')   row += 1;
    else                row += 0;
    if(str[1] == '1')   column += 8;
    else                column += 0;
    if(str[2] == '1')   column += 4;
    else                column += 0;
    if(str[3] == '1')   column += 2;
    else                column += 0;
    if(str[4] == '1')   column += 1;
    else                column += 0;
    int replace = S_box[number][row][column];
    switch(replace){
        case 0:  return "0000";
        case 1:  return "0001";
        case 2:  return "0010";
        case 3:  return "0011";
        case 4:  return "0100";
        case 5:  return "0101";
        case 6:  return "0110";
        case 7:  return "0111";
        case 8:  return "1000";
        case 9:  return "1001";
        case 10: return "1010";
        case 11: return "1011";
        case 12: return "1100";
        case 13: return "1101";
        case 14: return "1110";
        case 15: return "1111";
        default: return "0000";
    }
}
//S盒替换函数
string myreplace(string str) {
    string res = "";
    for(int i=0; i<8; ++i) {
        string tmp = str.substr(i*6, 6);
        string tmp_res = choice(tmp,i);
        res += tmp_res;
    }
    cout<<endl;
    cout<<"s盒替换:  ";
    display(res);
    cout<<endl;
    return res;
}
string encrypt(string l, string r, string k) {
    string res;
    r = expand(r);
    cout<<"扩展R：   ";
    display(r);
    cout<<endl;
    string tmp = add(r, k);
    res = myreplace(tmp);
    res = k_displace3(res);
    res = add(l,res);
    return res;
}
string _m_displace(string str) {
    string res = "";
    for(int i=0; i<64; ++i) {
        res += str[_IP[i]-1];
    }
    return res;
}
void display(string str) {
    for(int i=0; i<str.length(); ++i){
        cout<<str[i];
        if((i+1)%8 == 0)    cout<<' ';
    }
}
int main() {
    string m;       //明文 
    string k;       //密钥
    string c;       //密文
    string m_ip;    //置换后的明文
    string k_ip1;   //置换后的密钥
    string m_ip_l;  //L0
    string m_ip_r;  //R0
    string tmp_m_l; //L1-L16
    string tmp_m_r; //R1-R16
    string k_ip1_l; //C0
    string k_ip1_r; //D0
    string tmp_k_l; //C1-C16
    string tmp_k_r; //D1-D16
    string tmp_k;   //K1-K16


    cout<<"明文:     ";
    cin>>m;
    m_ip = m_displace(m);
    cout<<"初始置换: ";
    display(m_ip);
    cout<<endl;
    m_ip_l = m_ip.substr(0,32);
    m_ip_r = m_ip.substr(32);
    cout<<"L0:       ";
    display(m_ip_l);
    cout<<endl;
    cout<<"R0:       ";

    display(m_ip_r);
    cout<<endl;
    cout<<"密钥:     ";
    char space = cin.get();
    cin>>k;
    k_ip1 = k_displace1(k);
    cout<<"置换:     ";
    display(k_ip1);
    cout<<endl;
    k_ip1_l = k_ip1.substr(0,28);
    k_ip1_r = k_ip1.substr(28);
    cout<<"C0:       ";
    display(k_ip1_l);
    cout<<endl;
    cout<<"D0:       ";
    display(k_ip1_r);
    cout<<endl;
    tmp_k_l = k_ip1_l;
    tmp_k_r = k_ip1_r;
    tmp_m_l = m_ip_l;
    tmp_m_r = m_ip_r;
    for(int i=0; i<16; ++i){
        cout<<"N="<<i+1<<endl;
        tmp_k_l = rotate_left(tmp_k_l, i);
        tmp_k_r = rotate_left(tmp_k_r, i);
        tmp_k = k_displace2(tmp_k_l+tmp_k_r);
        cout<<"密钥:     ";
        display(tmp_k);
        cout<<endl;
        string tmp = tmp_m_l;
        tmp_m_l = tmp_m_r;
        tmp_m_r = encrypt(tmp, tmp_m_r, tmp_k);
        cout<<"L:        ";
        display(tmp_m_l);
        cout<<endl;
        cout<<"R:        ";
        display(tmp_m_r);
        cout<<endl<<endl;
    }
    c = _m_displace(tmp_m_r+tmp_m_l);
    cout<<"密文:     ";
    display(c);
    cout<<endl;
    return 0;
}